package cn.iocoder.yudao.module.iot.service.scene;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneActionCreateReqVO;
import cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneActionRespVO;
import cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneConditionCreateReqVO;
import cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneConditionRespVO;
import cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneCreateReqVO;
import cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneUpdateReqVO;
import cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneRespVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.scene.IotSceneActionDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.scene.IotSceneConditionDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.scene.IotSceneDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.scene.IotSceneLogDO;
import cn.iocoder.yudao.module.iot.dal.mysql.scene.IotSceneActionMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.scene.IotSceneConditionMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.scene.IotSceneLogMapper;
import cn.iocoder.yudao.module.iot.service.mqtt.IotMqttService;
import org.springframework.jdbc.core.JdbcTemplate;
import cn.iocoder.yudao.module.iot.dal.mysql.scene.IotSceneMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.Map;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.SCENE_NOT_EXISTS;
import cn.iocoder.yudao.module.iot.core.biz.dto.IotSceneRespDTO;
import cn.iocoder.yudao.module.iot.core.biz.dto.IotSceneActionDTO;
import cn.iocoder.yudao.module.iot.core.biz.dto.IotSceneConditionDTO;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;

/**
 * 场景 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class IotSceneServiceImpl implements IotSceneService {

    @Resource
    private IotSceneMapper sceneMapper;
    @Resource
    private IotSceneConditionMapper sceneConditionMapper;
    @Resource
    private IotSceneActionMapper sceneActionMapper;
    @Resource
    private IotSceneLogMapper sceneLogMapper;
    @Resource
    private cn.iocoder.yudao.module.iot.dal.mysql.product.IotUserProductMapper userProductMapper;
    @Resource
    private IotDeviceMapper deviceMapper;
    @Resource
    private IotProductMapper productMapper;
    
    @Resource
    private JdbcTemplate jdbcTemplate;

    @Resource
    private IotSceneTimerService iotSceneTimerService;

    @Resource
    private IotMqttService iotMqttService;

    @Override
    public Long createScene(IotSceneCreateReqVO createReqVO, Long userId) {
        // 插入场景
        IotSceneDO scene = BeanUtil.copyProperties(createReqVO, IotSceneDO.class);
        scene.setUserId(userId);
        sceneMapper.insert(scene);

        // 插入条件
        if (createReqVO.getConditions() != null) {
            for (IotSceneConditionCreateReqVO conditionReqVO : createReqVO.getConditions()) {
                IotSceneConditionDO condition = BeanUtil.copyProperties(conditionReqVO, IotSceneConditionDO.class);
                condition.setSceneId(scene.getId());
                // 手动set，防止字段名不一致
                condition.setProductId(conditionReqVO.getProductId());
                condition.setDeviceId(conditionReqVO.getDeviceId());
                condition.setAttr(conditionReqVO.getAttr());
                condition.setValue(conditionReqVO.getValue());
                condition.setConditionType(conditionReqVO.getConditionType());
                condition.setConditionValue(conditionReqVO.getConditionValue()); // 确保设置conditionValue
                condition.setOperator(conditionReqVO.getOperator());
                condition.setPriority(conditionReqVO.getPriority());
                sceneConditionMapper.insert(condition);
            }
        }

        // 插入动作
        if (createReqVO.getActions() != null) {
            for (int i = 0; i < createReqVO.getActions().size(); i++) {
                IotSceneActionCreateReqVO actionReqVO = createReqVO.getActions().get(i);
                IotSceneActionDO action = BeanUtil.copyProperties(actionReqVO, IotSceneActionDO.class);
                action.setSceneId(scene.getId());
                // 手动set，防止字段名不一致
                action.setProductId(actionReqVO.getProductId());
                action.setDeviceId(actionReqVO.getDeviceId());
                action.setAttr(actionReqVO.getAttr());
                action.setValue(actionReqVO.getValue());
                action.setActionType(actionReqVO.getActionType());
                action.setActionValue(actionReqVO.getActionValue());
                if (action.getOrderNum() == null) {
                    action.setOrderNum(i + 1);
                }
                sceneActionMapper.insert(action);
            }
        }

        // 发送MQTT消息通知设备
        sendSceneUpdateMessage(scene.getId());

        // 同步定时任务
        try {
            iotSceneTimerService.syncSceneTimer(scene.getId());
            log.info("[createScene][同步场景定时任务成功，场景ID: {}]", scene.getId());
        } catch (Exception e) {
            log.error("[createScene][同步场景定时任务失败，场景ID: {}]", scene.getId(), e);
        }

        return scene.getId();
    }

    @Override
    public void updateScene(IotSceneUpdateReqVO updateReqVO, Long userId) {
        // 校验场景存在
        IotSceneDO existingScene = validateSceneExists(updateReqVO.getId());

        // 校验用户权限
        if (existingScene.getUserId() != null && !existingScene.getUserId().equals(userId)) {
            throw new RuntimeException("无权限操作此场景");
        }

        // 更新场景基本信息
        IotSceneDO scene = BeanUtil.copyProperties(updateReqVO, IotSceneDO.class);
        scene.setUserId(userId);
        sceneMapper.updateById(scene);

        // 删除原有条件和动作
        sceneConditionMapper.deleteBySceneId(updateReqVO.getId());
        sceneActionMapper.deleteBySceneId(updateReqVO.getId());

        // 插入新的条件
        if (updateReqVO.getConditions() != null) {
            for (int i = 0; i < updateReqVO.getConditions().size(); i++) {
                IotSceneConditionCreateReqVO conditionReqVO = updateReqVO.getConditions().get(i);
                IotSceneConditionDO condition = BeanUtil.copyProperties(conditionReqVO, IotSceneConditionDO.class);
                condition.setSceneId(updateReqVO.getId());
                // 手动set，防止字段名不一致
                condition.setProductId(conditionReqVO.getProductId());
                condition.setDeviceId(conditionReqVO.getDeviceId());
                condition.setAttr(conditionReqVO.getAttr());
                condition.setValue(conditionReqVO.getValue());
                condition.setConditionType(conditionReqVO.getConditionType());
                condition.setConditionValue(conditionReqVO.getConditionValue()); // 确保设置conditionValue
                condition.setOperator(conditionReqVO.getOperator());
                if (condition.getPriority() == null) {
                    condition.setPriority(i + 1);
                }
                sceneConditionMapper.insert(condition);
            }
        }

        // 插入新的动作
        if (updateReqVO.getActions() != null) {
            for (int i = 0; i < updateReqVO.getActions().size(); i++) {
                IotSceneActionCreateReqVO actionReqVO = updateReqVO.getActions().get(i);
                IotSceneActionDO action = BeanUtil.copyProperties(actionReqVO, IotSceneActionDO.class);
                action.setSceneId(updateReqVO.getId());
                if (action.getOrderNum() == null) {
                    action.setOrderNum(i + 1);
                }
                sceneActionMapper.insert(action);
            }
        }

        // 发送MQTT消息通知设备
        sendSceneUpdateMessage(updateReqVO.getId());

        // 同步定时任务
        try {
            iotSceneTimerService.syncSceneTimer(updateReqVO.getId());
            log.info("[updateScene][同步场景定时任务成功，场景ID: {}]", updateReqVO.getId());
        } catch (Exception e) {
            log.error("[updateScene][同步场景定时任务失败，场景ID: {}]", updateReqVO.getId(), e);
        }

        log.info("更新场景成功，场景ID：{}，用户ID：{}", updateReqVO.getId(), userId);
    }

    @Override
    public void deleteScene(Long id) {
        // 校验存在
        validateSceneExists(id);

        // 删除场景
        sceneMapper.deleteById(id);
        // 删除条件
        sceneConditionMapper.deleteBySceneId(id);
        // 删除动作
        sceneActionMapper.deleteBySceneId(id);

        // 发送MQTT消息通知设备
        sendSceneDeleteMessage(id);

        // 清理定时任务
        try {
            iotSceneTimerService.deleteSceneTimer(id);
            log.info("[deleteScene][清理场景定时任务成功，场景ID: {}]", id);
        } catch (Exception e) {
            log.error("[deleteScene][清理场景定时任务失败，场景ID: {}]", id, e);
        }
    }

    @Override
    public IotSceneDO getScene(Long id) {
        return sceneMapper.selectById(id);
    }

    @Override
    public IotSceneRespVO getSceneDetail(Long id) {
        // 校验存在
        IotSceneDO scene = validateSceneExists(id);

        // 获取条件列表
        List<IotSceneConditionDO> conditions = sceneConditionMapper.selectListBySceneId(id);
        List<IotSceneConditionRespVO> conditionRespVOs = BeanUtil.copyToList(conditions, IotSceneConditionRespVO.class);
        for (int i = 0; i < conditions.size(); i++) {
            IotSceneConditionDO c = conditions.get(i);
            IotSceneConditionRespVO v = conditionRespVOs.get(i);
            v.setProductId(c.getProductId());
            v.setDeviceId(c.getDeviceId());
            v.setAttr(c.getAttr());
            v.setValue(c.getValue());
            v.setOperator(c.getOperator());
        }

        // 获取动作列表
        List<IotSceneActionDO> actions = sceneActionMapper.selectListBySceneId(id);
        List<IotSceneActionRespVO> actionRespVOs = BeanUtil.copyToList(actions, IotSceneActionRespVO.class);
        for (int i = 0; i < actions.size(); i++) {
            IotSceneActionDO a = actions.get(i);
            IotSceneActionRespVO v = actionRespVOs.get(i);
            v.setProductId(a.getProductId());
            v.setDeviceId(a.getDeviceId());
            v.setAttr(a.getAttr());
            v.setValue(a.getValue());
        }

        // 批量查设备信息
        List<Long> deviceIds = conditionRespVOs.stream()
            .map(IotSceneConditionRespVO::getDeviceId)
            .collect(Collectors.toList());
        deviceIds.addAll(actionRespVOs.stream()
            .map(IotSceneActionRespVO::getDeviceId)
            .collect(Collectors.toList()));
        deviceIds = deviceIds.stream().filter(deviceId -> deviceId != null).distinct().collect(Collectors.toList());
        
        // 1. 查询iot_device表获取设备名称
        Map<Long, String> deviceNameMap = deviceIds.isEmpty() ? Map.of() :
            deviceMapper.selectList(new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO>()
                .in(cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO::getId, deviceIds))
                .stream().collect(Collectors.toMap(
                    cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO::getId,
                    cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO::getDeviceName,
                    (v1, v2) -> v1));
        
        // 2. 查询iot_user_device表获取自定义设备名称
        final Map<Long, String> userDeviceNameMap = getDeviceNameMapFromUserDevice(deviceIds);
        
        // set 名称到VO，优先使用iot_user_device表的custom_device_name
        final Map<Long, String> finalDeviceNameMap = deviceNameMap;
        conditionRespVOs.forEach(cond -> {
            if (cond.getDeviceId() != null) {
                cond.setDeviceName(userDeviceNameMap.getOrDefault(cond.getDeviceId(), finalDeviceNameMap.get(cond.getDeviceId())));
            } else {
                // 对于定时条件，设备ID为null，设置默认名称
                cond.setDeviceName("定时触发");
            }
            // 不再设置产品名称，因为前端已经不需要显示产品信息
        });
        actionRespVOs.forEach(act -> {
            if (act.getDeviceId() != null) {
                act.setDeviceName(userDeviceNameMap.getOrDefault(act.getDeviceId(), finalDeviceNameMap.get(act.getDeviceId())));
            } else {
                // 对于没有设备ID的动作，设置默认名称
                act.setDeviceName("未知设备");
            }
            // 不再设置产品名称，因为前端已经不需要显示产品信息
        });

        // 调试输出
        System.out.println("条件VO: " + cn.hutool.json.JSONUtil.toJsonStr(conditionRespVOs));
        System.out.println("动作VO: " + cn.hutool.json.JSONUtil.toJsonStr(actionRespVOs));

        // 组装返回
        IotSceneRespVO respVO = BeanUtil.copyProperties(scene, IotSceneRespVO.class);
        respVO.setConditions(conditionRespVOs);
        respVO.setActions(actionRespVOs);
        return respVO;
    }

    @Override
    public List<IotSceneRespVO> getSceneList(Long userId) {
        List<IotSceneDO> scenes = sceneMapper.selectListByUserId(userId);
        return scenes.stream().map(scene -> {
            IotSceneRespVO respVO = BeanUtil.copyProperties(scene, IotSceneRespVO.class);
            // 获取动作数量
            List<IotSceneActionDO> actions = sceneActionMapper.selectListBySceneId(scene.getId());
            respVO.setActions(BeanUtil.copyToList(actions, IotSceneActionRespVO.class));
            return respVO;
        }).collect(Collectors.toList());
    }

    @Override
    public void executeScene(Long id, Long userId) {
        // 校验存在
        IotSceneDO scene = validateSceneExists(id);
        log.info("[executeScene][开始执行场景，场景ID: {}, 用户ID: {}, 场景状态: {}]", id, userId, scene.getStatus());

        long startTime = System.currentTimeMillis();
        String executeResult = "SUCCESS";
        String errorMessage = null;

        try {
            // 获取场景动作
            List<IotSceneActionDO> actions = sceneActionMapper.selectListBySceneId(id);
            log.info("[executeScene][获取到场景动作数量: {}, 场景ID: {}]", actions.size(), id);
            
            // 执行动作
            for (IotSceneActionDO action : actions) {
                try {
                    executeAction(action);
                    // 延迟执行
                    if (action.getDelay() != null && action.getDelay() > 0) {
                        Thread.sleep(action.getDelay() * 1000L);
                    }
                } catch (Exception e) {
                    log.error("执行场景动作失败，场景ID：{}，动作ID：{}", id, action.getId(), e);
                    executeResult = "PARTIAL";
                    errorMessage = StrUtil.isBlank(errorMessage) ? e.getMessage() : errorMessage + ";" + e.getMessage();
                }
            }
            
            log.info("[executeScene][场景动作执行完成，开始检查单次执行，场景ID: {}]", id);
            
            // 检查是否为单次执行，如果是则禁用场景
            checkAndDisableSingleExecutionScene(scene);
            
            log.info("[executeScene][场景执行完成，场景ID: {}, 执行结果: {}]", id, executeResult);
            
        } catch (Exception e) {
            log.error("执行场景失败，场景ID：{}", id, e);
            executeResult = "FAILED";
            errorMessage = e.getMessage();
        }

        // 记录执行日志
        IotSceneLogDO log = IotSceneLogDO.builder()
                .sceneId(id)
                .sceneName(scene.getName())
                .triggerType("TIMER") // 修改为定时触发
                .triggerCondition("定时触发")
                .executeResult(executeResult)
                .executeTime(LocalDateTime.now())
                .duration((int) (System.currentTimeMillis() - startTime))
                .errorMessage(errorMessage)
                .userId(userId)
                .build();
        sceneLogMapper.insert(log);
    }
    
    /**
     * 检查并禁用单次执行的场景
     */
    private void checkAndDisableSingleExecutionScene(IotSceneDO scene) {
        try {
            log.info("[checkAndDisableSingleExecutionScene][开始检查场景，场景ID: {}, 当前状态: {}]", scene.getId(), scene.getStatus());
            
            // 获取场景的定时条件
            List<IotSceneConditionDO> timerConditions = sceneConditionMapper.selectList(
                new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<IotSceneConditionDO>()
                    .eq(IotSceneConditionDO::getSceneId, scene.getId())
                    .eq(IotSceneConditionDO::getConditionType, "TIMER")
            );
            
            log.info("[checkAndDisableSingleExecutionScene][找到定时条件数量: {}, 场景ID: {}]", timerConditions.size(), scene.getId());
            
            for (IotSceneConditionDO condition : timerConditions) {
                log.info("[checkAndDisableSingleExecutionScene][检查条件，条件ID: {}, 条件值: {}]", condition.getId(), condition.getConditionValue());
                
                if (condition.getConditionValue() != null) {
                    try {
                        // 安全解析JSON
                        Map<String, Object> conditionValue = null;
                        String jsonStr = condition.getConditionValue();
                        if (jsonStr.startsWith("{") && jsonStr.endsWith("}")) {
                            @SuppressWarnings("unchecked")
                            Map<String, Object> parsed = JSONUtil.toBean(jsonStr, Map.class);
                            conditionValue = parsed;
                        }
                        
                        if (conditionValue != null) {
                        String executionMode = (String) conditionValue.get("executionMode");
                            
                            log.info("[checkAndDisableSingleExecutionScene][解析执行模式: {}, 场景ID: {}]", executionMode, scene.getId());
                        
                        // 如果是单次执行，则禁用场景
                        if ("once".equals(executionMode)) {
                            log.info("[checkAndDisableSingleExecutionScene][单次执行场景，禁用场景，场景ID: {}]", scene.getId());
                            scene.setStatus(0);
                                int updateResult = sceneMapper.updateById(scene);
                                log.info("[checkAndDisableSingleExecutionScene][场景状态更新结果: {}, 场景ID: {}]", updateResult, scene.getId());
                            return;
                            } else {
                                log.info("[checkAndDisableSingleExecutionScene][非单次执行场景，执行模式: {}, 场景ID: {}]", executionMode, scene.getId());
                            }
                        } else {
                            log.warn("[checkAndDisableSingleExecutionScene][JSON解析失败，场景ID: {}, 条件ID: {}]", scene.getId(), condition.getId());
                        }
                    } catch (Exception e) {
                        log.warn("[checkAndDisableSingleExecutionScene][解析条件值失败，场景ID: {}, 条件ID: {}]", scene.getId(), condition.getId(), e);
                    }
                } else {
                    log.warn("[checkAndDisableSingleExecutionScene][条件值为空，场景ID: {}, 条件ID: {}]", scene.getId(), condition.getId());
                }
            }
            
            log.info("[checkAndDisableSingleExecutionScene][场景检查完成，未找到单次执行模式，场景ID: {}]", scene.getId());
            
        } catch (Exception e) {
            log.error("[checkAndDisableSingleExecutionScene][检查单次执行场景失败，场景ID: {}]", scene.getId(), e);
        }
    }

    @Override
    public java.util.List<cn.iocoder.yudao.module.iot.dal.dataobject.scene.IotSceneActionDO> getSceneActions(Long sceneId) {
        return sceneActionMapper.selectListBySceneId(sceneId);
    }

    @Override
    public java.util.List<cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneRespVO> getScenesByDeviceId(Long deviceId) {
        // 1. 查找该设备相关的所有条件
        List<IotSceneConditionDO> conditions = sceneConditionMapper.selectList(
            new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<IotSceneConditionDO>()
                .eq(IotSceneConditionDO::getDeviceId, deviceId)
        );
        if (conditions.isEmpty()) {
            log.info("设备ID:{} 未找到任何条件", deviceId);
            return Collections.emptyList();
        }
        // 2. 获取所有相关的场景ID
        Set<Long> sceneIds = conditions.stream().map(IotSceneConditionDO::getSceneId).collect(Collectors.toSet());
        if (sceneIds.isEmpty()) {
            log.info("设备ID:{} 未找到任何相关场景", deviceId);
            return Collections.emptyList();
        }
        // 3. 查询场景表
        List<IotSceneDO> scenes = sceneMapper.selectList(
            new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<IotSceneDO>()
                .in(IotSceneDO::getId, sceneIds)
        );
        // 4. 查询每个场景的动作，并组装返回
        List<cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneRespVO> result = new ArrayList<>();
        for (IotSceneDO scene : scenes) {
            // 该场景下所有条件
            List<IotSceneConditionDO> sceneConds = conditions.stream().filter(c -> c.getSceneId().equals(scene.getId())).collect(Collectors.toList());
            // 该场景下所有动作
            List<IotSceneActionDO> actions = sceneActionMapper.selectListBySceneId(scene.getId());
            // 转VO
            List<IotSceneConditionRespVO> condVOs = BeanUtil.copyToList(sceneConds, IotSceneConditionRespVO.class);
            List<IotSceneActionRespVO> actionVOs = BeanUtil.copyToList(actions, IotSceneActionRespVO.class);
            // 日志打印
            log.info("场景ID:{} 条件:{} 动作:{}", scene.getId(), JSONUtil.toJsonStr(condVOs), JSONUtil.toJsonStr(actionVOs));
            // 组装VO
            IotSceneRespVO vo = BeanUtil.copyProperties(scene, IotSceneRespVO.class);
            vo.setConditions(condVOs);
            vo.setActions(actionVOs);
            result.add(vo);
        }
        return result;
    }

    @Override
    public java.util.List<IotSceneRespDTO> getScenesAndActionsByDeviceId(Long deviceId) {
        log.info("开始查询设备ID:{} 的场景和动作", deviceId);
        
        java.util.List<Long> actionSceneIds = sceneActionMapper.selectListByDeviceId(deviceId)
            .stream().map(IotSceneActionDO::getSceneId).distinct().toList();
        log.info("设备ID:{} 找到动作场景ID:{}", deviceId, actionSceneIds);
        
        java.util.List<Long> conditionSceneIds = sceneConditionMapper.selectList(new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<IotSceneConditionDO>()
            .eq(IotSceneConditionDO::getDeviceId, deviceId))
            .stream().map(IotSceneConditionDO::getSceneId).distinct().toList();
        log.info("设备ID:{} 找到条件场景ID:{}", deviceId, conditionSceneIds);
        
        java.util.Set<Long> allSceneIds = new java.util.HashSet<>();
        allSceneIds.addAll(actionSceneIds);
        allSceneIds.addAll(conditionSceneIds);
        log.info("设备ID:{} 合并后所有场景ID:{}", deviceId, allSceneIds);
        
        if (allSceneIds.isEmpty()) {
            log.info("设备ID:{} 未找到任何相关场景", deviceId);
            return java.util.Collections.emptyList();
        }
        
        java.util.List<IotSceneDO> scenes = sceneMapper.selectList(
            new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<IotSceneDO>()
                .in(IotSceneDO::getId, allSceneIds)
        );
        log.info("设备ID:{} 查询到场景数量:{}", deviceId, scenes.size());
        
        java.util.List<IotSceneRespDTO> result = new java.util.ArrayList<>();
        for (var scene : scenes) {
            log.info("处理场景ID:{}", scene.getId());
            
            IotSceneRespDTO dto = BeanUtils.toBean(scene, IotSceneRespDTO.class);
            var actions = sceneActionMapper.selectListBySceneId(scene.getId())
                .stream().map(actionDO -> BeanUtils.toBean(actionDO, IotSceneActionDTO.class)).toList();
            var conditions = sceneConditionMapper.selectListBySceneId(scene.getId())
                .stream().map(condDO -> BeanUtils.toBean(condDO, IotSceneConditionDTO.class)).toList();
            
            dto.setActions(actions);
            dto.setConditions(conditions);
            
            log.info("设备ID:{} 场景ID:{} 条件:{} 动作:{}", deviceId, scene.getId(), cn.hutool.json.JSONUtil.toJsonStr(conditions), cn.hutool.json.JSONUtil.toJsonStr(actions));
            result.add(dto);
        }
        
        log.info("设备ID:{} 最终返回结果数量:{}", deviceId, result.size());
        return result;
    }

    private IotSceneDO validateSceneExists(Long id) {
        IotSceneDO scene = sceneMapper.selectById(id);
        if (scene == null) {
            throw exception(SCENE_NOT_EXISTS);
        }
        return scene;
    }

    private void executeAction(IotSceneActionDO action) {
        // 直接调用设备控制接口，不经过网关消息总线
        try {
            // 构建控制命令
            String command;
            if ("control".equals(action.getActionType())) {
                // 如果是control类型，构建JSON命令
                command = String.format("{\"control\": \"%s\"}", action.getActionValue());
            } else {
                // 其他类型，使用attr和value
                command = String.format("{\"%s\": \"%s\"}", action.getAttr(), action.getValue());
            }
            
            // 直接调用设备控制服务
            IotDeviceService deviceService = SpringUtil.getBean(IotDeviceService.class);
            deviceService.controlDeviceDirect(action.getDeviceId(), command);
            
            log.info("[executeAction][定时任务直接控制设备成功，设备ID: {}, 动作类型: {}, 动作值: {}, 命令: {}]", 
                action.getDeviceId(), action.getActionType(), action.getActionValue(), command);
                
        } catch (Exception e) {
            log.error("[executeAction][定时任务直接控制设备失败，设备ID: {}, 动作类型: {}, 动作值: {}]", 
                action.getDeviceId(), action.getActionType(), action.getActionValue(), e);
            throw new RuntimeException("定时任务控制设备失败: " + e.getMessage());
        }
    }

    private void sendSceneUpdateMessage(Long sceneId) {
        // 发送场景更新MQTT消息
        iotMqttService.sendSceneUpdateMessage(sceneId);
    }

    private void sendSceneDeleteMessage(Long sceneId) {
        // 发送场景删除MQTT消息
        iotMqttService.sendSceneDeleteMessage(sceneId);
    }

    @Override
    public void updateSceneStatus(Long id, Integer status, Long userId) {
        // 校验场景存在
        IotSceneDO scene = validateSceneExists(id);

        // 校验用户权限（可选：检查场景是否属于当前用户）
        if (scene.getUserId() != null && !scene.getUserId().equals(userId)) {
            throw new RuntimeException("无权限操作此场景");
        }

        // 更新状态
        IotSceneDO updateObj = new IotSceneDO();
        updateObj.setId(id);
        updateObj.setStatus(status);
        sceneMapper.updateById(updateObj);

        // 发送MQTT消息通知设备
        sendSceneUpdateMessage(id);

        log.info("更新场景状态成功，场景ID：{}，状态：{}，用户ID：{}", id, status, userId);
    }
    
    /**
     * 从iot_user_device表获取设备名称映射
     * @param deviceIds 设备ID列表
     * @return 设备ID到设备名称的映射
     */
    private Map<Long, String> getDeviceNameMapFromUserDevice(List<Long> deviceIds) {
        if (deviceIds.isEmpty()) {
            return Map.of();
        }
        
        try {
            // 使用JdbcTemplate查询iot_user_device表
            String sql = "SELECT device_id, custom_device_name FROM iot_user_device WHERE device_id IN (" +
                String.join(",", Collections.nCopies(deviceIds.size(), "?")) + ") AND deleted = 0";
            List<Map<String, Object>> userDevices = jdbcTemplate.queryForList(sql, deviceIds.toArray());
            return userDevices.stream().collect(Collectors.toMap(
                row -> {
                    Object deviceIdObj = row.get("device_id");
                    if (deviceIdObj instanceof java.math.BigInteger) {
                        return ((java.math.BigInteger) deviceIdObj).longValue();
                    } else if (deviceIdObj instanceof Number) {
                        return ((Number) deviceIdObj).longValue();
                    } else {
                        return Long.valueOf(deviceIdObj.toString());
                    }
                },
                row -> (String) row.get("custom_device_name"),
                (v1, v2) -> v1));
        } catch (Exception e) {
            log.warn("查询iot_user_device表失败", e);
            return Map.of();
        }
    }

    @Override
    public java.util.List<cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneRespVO> getEnabledScenes() {
        // 查询所有启用的场景（状态为1）
        List<IotSceneDO> enabledScenes = sceneMapper.selectList(
            new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<IotSceneDO>()
                .eq(IotSceneDO::getStatus, 1) // 只查询启用的场景
        );
        
        log.info("查询到{}个启用的场景", enabledScenes.size());
        
        // 转换为VO对象
        List<cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneRespVO> result = new java.util.ArrayList<>();
        for (IotSceneDO scene : enabledScenes) {
            cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneRespVO vo = BeanUtils.toBean(scene, cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneRespVO.class);
            
            // 获取场景的条件和动作
            var conditions = sceneConditionMapper.selectListBySceneId(scene.getId());
            var actions = sceneActionMapper.selectListBySceneId(scene.getId());
            
            // 设置条件和动作信息
            vo.setConditions(conditions.stream()
                .map(cond -> BeanUtils.toBean(cond, cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneConditionRespVO.class))
                .collect(java.util.stream.Collectors.toList()));
            vo.setActions(actions.stream()
                .map(action -> BeanUtils.toBean(action, cn.iocoder.yudao.module.iot.controller.app.scene.vo.IotSceneActionRespVO.class))
                .collect(java.util.stream.Collectors.toList()));
            
            result.add(vo);
        }
        
        log.info("返回{}个启用的场景详情", result.size());
        return result;
    }

}